﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Space_Conquest
{
    class Laborer : GroundUnit
    {

        public static Texture _textureLaborer = new Texture("Images/Ground/Laborerone.bmp");

        protected static Texture _metalBar = new Texture("Images/MetalBar.bmp");
        protected static Texture _oilBar = new Texture("Images/OilBar.bmp");

        #region Properties

        public int ResourceAmountGathered
        {
            get
            {
                return _resourceAmountGathered;
            }
        }

        #endregion

        #region Private Members

        ResourceUnit _resourceUnitCollectingFrom;
        ResourceType _resourceCurrentlyCollecting;
        int _resourceAmountGathered;
        TownCenter _resourceDropPoint;

        BuildingUnit _buildingCreating;

        #endregion

        #region Constructor

        public Laborer(int x, int y, Player owner)
            : base(_textureLaborer, x, y, owner)
        {

            _hitPoints = _maxHitPoints = 30;
            
            _attackDamage = 2;
            _attackDelay = 15;
            _defense = 2;

            _visionRange = 2;
            _speed = 3;
            _area.Height = 1;
            _area.Width = 1;
            _layer = UnitLayer.Ground;

            SetLocation();

        } 

        #endregion

        #region Methods

        public void GatherResource(ResourceUnit resourceUnit)
        {


            // Keep a reference to the actual resource unit
            _resourceUnitCollectingFrom = resourceUnit;

            // Figure out what type of resource is being collected
            if (resourceUnit is Metal)
            {
                if (_resourceCurrentlyCollecting != ResourceType.Metal)
                    _resourceAmountGathered = 0;
                _resourceCurrentlyCollecting = ResourceType.Metal;
            }
            else if (resourceUnit is OilField)
            {
                if (_resourceCurrentlyCollecting != ResourceType.Fuel)
                    _resourceAmountGathered = 0;
                _resourceCurrentlyCollecting = ResourceType.Fuel;
            }

            // Indicate that unit should gather.
            ClearAndResetState(UnitState.Gather);


        }

        public void BuildBuilding(BuildingUnit buildingUnit)
        {

            // Set the building unit to build
            _buildingCreating = buildingUnit;

            // Indicate that unit should build.
            ClearAndResetState(UnitState.Build);

        }

        public override void Motion()
        {

            bool tookAction = false;

            // Only continue if Unit has something to do
            while (!_state.UnitIsStill() && !tookAction)
            {

                switch (_state.Peek())
                {
                    case UnitState.Gather:

                        // Check if resource is still there
                        if (_resourceUnitCollectingFrom.IsAlive)
                        {

                            // Check amount carrying
                            if (_resourceAmountGathered < 100)
                            {
                                // Gather from ResourceUnit
                                if (_area.GetScalarPoint().IsAdjacentTo(_resourceUnitCollectingFrom.MapPoint))
                                {
                                    // Push GatherWork
                                    _state.Push(UnitState.GatherWork);
                                }
                                else
                                {
                                    // Move to closest tile around ResourceUnit
                                    _destPoint = _resourceUnitCollectingFrom.GetClosestAdjacentAvailablePoint(this.MapPoint);
                                    if (_destPoint == null)
                                        _destPoint = _resourceUnitCollectingFrom.MapArea.GetClosestAdjacentPoint(this.MapPoint);
                                    _state.Push(UnitState.MoveToTile);
                                }
                            }
                            else
                            {
                                // Return to Town Center

                                if ((_resourceDropPoint == null) ||
                                    (!_resourceDropPoint.MapArea.IsAdjacentTo(_area)))
                                {
                                    // get a list of Town Centers
                                    var townCenters =
                                        from u in Parent.Parent.UnitManager.Units
                                        where this.Owner == u.Owner && 
                                              u is TownCenter &&
                                              u.IsAlive
                                        select u;

                                    Unit closestTownCenter =
                                        _area.FindClosestUnit(townCenters.ToArray());

                                    if (closestTownCenter != null)
                                    {

                                        _destPoint = closestTownCenter.GetClosestAdjacentAvailablePoint(this.MapPoint);
                                        if (_destPoint == null)
                                            _destPoint = closestTownCenter.MapArea.GetClosestAdjacentPoint(this.MapPoint);
                                        _resourceDropPoint = (TownCenter)closestTownCenter;

                                        _state.Push(UnitState.MoveToTile);

                                    }
                                    else
                                    {

                                        // No towncenter left, need to stop
                                        _state.Pop();

                                    }

                                }
                                else
                                {

                                    if (_resourceDropPoint.IsAlive)
                                    {

                                        if (_resourceCurrentlyCollecting == ResourceType.Metal)
                                            _owner.Metal += (_resourceAmountGathered / 10);
                                        else if (_resourceCurrentlyCollecting == ResourceType.Fuel)
                                            _owner.Fuel += (_resourceAmountGathered / 10);

                                        _resourceAmountGathered = 0;

                                    }
                                    else
                                    {
                                        _resourceDropPoint = null;
                                    }

                                }

                            }

                        }
                        else
                        {

                            // Resource this laborer was gathering from is depleted,
                            // Attempt to find a new resource of the same type, and gather from that.

                            var resources = 
                                from r in Parent.Parent.UnitManager.Units
                                where r.GetType() == _resourceUnitCollectingFrom.GetType() &&
                                      r.MapPoint.DistanceBetween(MapPoint) < 6.0 &&
                                      r.IsAlive
                                select r;

                            if (resources.Count() > 0)
                            {

                                // Found at least one resource of same type near by

                                ResourceUnit closestResource = null;
                                double closestDistance = 7.0;

                                foreach (ResourceUnit r in resources)
                                {
                                    if (r.MapPoint.DistanceBetween(MapPoint) < closestDistance)
                                    {
                                        closestResource = r;
                                        closestDistance = r.MapPoint.DistanceBetween(MapPoint);
                                    }
                                }

                                // Calculated the closest one, now going to it
                                _resourceUnitCollectingFrom = closestResource;

                            }
                            else
                            {

                                // Couldn't find anything, time to quit
                                _state.Pop();

                            }

                        }

                        break;
                    case UnitState.GatherWork:
                        if (_resourceUnitCollectingFrom.IsAlive)
                        {
                        
                            if (_resourceAmountGathered < 100)
                                ++_resourceAmountGathered;
                            else
                                _state.Pop();

                            if (_resourceAmountGathered % 30 == 0)
                            {
                                if(_resourceCurrentlyCollecting == ResourceType.Metal)
                                    Parent.Parent.LocalPlayer.PlaySound("Sounds/Metal.wav", _resourceUnitCollectingFrom.MapPoint);
                                else if (_resourceCurrentlyCollecting == ResourceType.Fuel)
                                    Parent.Parent.LocalPlayer.PlaySound("Sounds/Oil.wav", _resourceUnitCollectingFrom.MapPoint);
                            }

                            _resourceUnitCollectingFrom.TakeHit(1);
                            tookAction = true;
                        
                        }
                        else
                        {
                            _state.Pop();
                        }
                        break;
                    case UnitState.Build:
                        {

                            if ((!_buildingCreating.IsBuilt) && (_buildingCreating.IsAlive))
                            {

                                // if not next to building unit
                                if (!_area.IsAdjacentTo(_buildingCreating.MapArea))
                                {

                                    // Move to closest tile around ResourceUnit
                                    _destPoint = _buildingCreating.GetClosestAdjacentAvailablePoint(this.MapPoint);
                                    if (_destPoint == null)
                                        _destPoint = _resourceUnitCollectingFrom.MapArea.GetClosestAdjacentPoint(this.MapPoint);
                                    _state.Push(UnitState.MoveToTile);

                                }
                                else
                                {
                                    // push building
                                    _state.Push(UnitState.Building);
                                }

                            }
                            else
                            {

                                //Built, stop building (look for others to build around area later?)
                                _state.Pop();

                            }

                        }
                        break;
                    case UnitState.Building:
                        {

                            if ((!_buildingCreating.IsBuilt) && (_buildingCreating.IsAlive))
                            {

                                // Build a little of building
                                _buildingCreating.BuildTick();
                                tookAction = true;

                            }
                            else
                            {
                                // Finish, return
                                _state.Pop();

                            }


                        }
                        break;
                    default:
                        base.Motion();
                        tookAction = true;
                        break;
                }

            }

        }

        public void RenderResourceBar()
        {

            if (_resourceAmountGathered > 0)
            {

                _barSprite.Alpha = 200;
                _barSprite.Left = _sprite.Left; _barSprite.Top = _sprite.Top + 9;
                _barSprite.Height = 4;
                _barSprite.Width = (int)((double)(_sprite.Width) * ((double)_resourceAmountGathered) / 100);
                if (_barSprite.Width <= 0)
                    _barSprite.Width = 1;
                
                if(_resourceCurrentlyCollecting == ResourceType.Fuel)
                    _barSprite.Render(_oilBar);
                else if (_resourceCurrentlyCollecting == ResourceType.Metal)
                    _barSprite.Render(_metalBar);

                _barSprite.Alpha = 255;
                _barSprite.Top -= 4;
                _barSprite.Width = _sprite.Width; _barSprite.Height = 12;
                _barSprite.Render(_unitBar);

            }

        }
 

        #endregion

    }
}
